home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Diamond Collection / The Diamond Collection (Software Vault)(Digital Impact).ISO / cdr44 / frasrc19.zip / MISCRES.C < prev    next >
Text File  |  1995-03-08  |  47KB  |  1,558 lines

  1. /*
  2.     Resident odds and ends that don't fit anywhere else.
  3. */
  4.  
  5. #include <string.h>
  6. #include <stdlib.h>
  7. #include <stdio.h>
  8. #include <ctype.h>
  9. #include <time.h>
  10. #include <malloc.h>
  11. #ifndef XFRACT
  12. #include <stdarg.h>
  13. #include <io.h>
  14. #include <dos.h>
  15. #else
  16. #include <varargs.h>
  17. #endif
  18. #include <math.h>
  19. /*#ifdef __TURBOC__
  20. #include <dir.h>
  21. #endif  */
  22.  
  23. #include "fractint.h"
  24. #include "fractype.h"
  25. #include "helpdefs.h"
  26. #include "prototyp.h"
  27.  
  28. /* routines in this module    */
  29.  
  30. static    void trigdetails(char *);
  31. static void area(void);
  32. static int find_one_file_item(char *, char *, FILE **);
  33.  
  34. /* TW's static string consolidation campaign to help brain-dead compilers */
  35. char s_cantwrite[]      = {"Can't write %s"};
  36. char s_cantcreate[]     = {"Can't create %s"};
  37. char s_cantunderstand[] = {"Can't understand %s"};
  38. char s_cantfind[]       = {"Can't find %s"};
  39.  
  40. #ifndef XFRACT
  41.  
  42. void findpath(char far *filename, char *fullpathname) /* return full pathnames */
  43. {
  44.    char fname[FILE_MAX_FNAME];
  45.    char ext[FILE_MAX_EXT];
  46.    char temp_path[FILE_MAX_PATH];
  47.  
  48.    /* first try current directory */
  49.    splitpath(filename ,NULL,NULL,fname,ext);
  50.    makepath(temp_path,""   ,"" ,fname,ext);
  51.    if(access(temp_path,0)==0) {   /* file exists */
  52.       strcpy(fullpathname,temp_path);
  53.       return;
  54.    }
  55.  
  56.    far_strcpy(temp_path,filename);   /* avoid side effect changes to filename */
  57.    if (temp_path[0] == SLASHC || (temp_path[0] && temp_path[1] == ':')) {
  58.       if(access(temp_path,0)==0) {   /* file exists */
  59.          strcpy(fullpathname,temp_path);
  60.          return;
  61.          }
  62.       else {
  63.          splitpath(temp_path ,NULL,NULL,fname,ext);
  64.          makepath(temp_path,""   ,"" ,fname,ext);
  65.          }
  66.       }
  67.    fullpathname[0] = 0;             /* indicate none found */
  68. /* #ifdef __TURBOC__ */                /* look for the file */
  69. /*   strcpy(fullpathname,searchpath(temp_path)); */
  70. /* #else */
  71.    _searchenv(temp_path,"PATH",fullpathname);
  72. /* #endif */
  73.    if (fullpathname[0] != 0)            /* found it! */
  74.       if (strncmp(&fullpathname[2],SLASHSLASH,2) == 0) /* stupid klooge! */
  75.      strcpy(&fullpathname[3],temp_path);
  76. }
  77. #endif
  78.  
  79.  
  80. void notdiskmsg()
  81. {
  82. static FCODE sorrymsg[]={
  83. "This type may be slow using a real-disk based 'video' mode, but may not \n\
  84. be too bad if you have enough expanded or extended memory. Press <Esc> to \n\
  85. abort if it appears that your disk drive is working too hard."};
  86.    stopmsg(0,sorrymsg);
  87. }
  88.  
  89. /* Wrapping version of putstring for long numbers                         */
  90. /* row     -- pointer to row variable, internally incremented if needed   */
  91. /* col1    -- starting column                                             */
  92. /* col2    -- last column                                                 */
  93. /* color   -- attribute (same as for putstring)                           */
  94. /* maxrow -- max number of rows to write                                 */
  95. /* returns 0 if success, 1 if hit maxrow before done                      */
  96. int putstringwrap(int *row,int col1,int col2,int color,char far *str,int maxrow)
  97. {
  98.     char save1, save2;
  99.     int length, decpt, padding, startrow, done;
  100.     done = 0;
  101.     startrow = *row;
  102.     length = far_strlen(str);
  103.     padding = 3; /* space between col1 and decimal. */
  104.     /* find decimal point */
  105.     for(decpt=0;decpt < length; decpt++)
  106.        if(str[decpt] == '.')
  107.           break;
  108.     if(decpt >= length)
  109.        decpt = 0;
  110.     if(decpt < padding)
  111.        padding -= decpt;   
  112.     else
  113.        padding = 0;
  114.     col1 += padding;   
  115.     decpt += col1+1; /* column just past where decimal is */         
  116.     while(length > 0)
  117.     {
  118.        if(col2-col1 < length)
  119.        {
  120.           if((*row - startrow + 1) >= maxrow)
  121.              done = 1;
  122.           else
  123.              done = 0;
  124.           save1 = str[col2-col1+1];
  125.           save2 = str[col2-col1+2];
  126.           if(done)
  127.              str[col2-col1+1]   = '+';
  128.           else
  129.              str[col2-col1+1]   = '\\';
  130.           str[col2-col1+2] = 0;
  131.           putstring(*row,col1,color,str);
  132.           if(done == 1)
  133.              break;
  134.           str[col2-col1+1] = save1;
  135.           str[col2-col1+2] = save2;
  136.           str += col2-col1;
  137.           (*row)++;
  138.        } else
  139.           putstring(*row,col1,color,str);
  140.        length -= col2-col1;
  141.        col1 = decpt; /* align with decimal */
  142.     }
  143.     return(done);
  144. }
  145.  
  146. #define rad_to_deg(x) ((x)*(180/PI)) /* most people "think" in degrees */
  147. #define deg_to_rad(x) ((x)*(PI/180))
  148. /*
  149. convert corners to center/mag
  150. Rotation angles indicate how much the IMAGE has been rotated, not the
  151. zoom box.  Same goes for the Skew angles
  152. */
  153.  
  154. #ifdef _MSC_VER
  155. #pragma optimize( "", off )
  156. #endif
  157.  
  158. void cvtcentermag(double *Xctr, double *Yctr, LDBL *Magnification, double *Xmagfactor, double *Rotation, double *Skew)
  159. {
  160.    double Width, Height;
  161.    double a, b; /* bottom, left, diagonal */
  162.    double a2, b2, c2; /* squares of above */
  163.    double tmpx, tmpy, tmpa; /* temporary x, y, angle */
  164.  
  165.    /* simple normal case first */
  166.    if (xx3rd == xxmin && yy3rd == yymin)
  167.    { /* no rotation or skewing, but stretching is allowed */
  168.       Width  = xxmax - xxmin;
  169.       Height = yymax - yymin;
  170.       *Xctr = (xxmin + xxmax)/2;
  171.       *Yctr = (yymin + yymax)/2;
  172.       *Magnification  = 2/Height;
  173.       *Xmagfactor =  Height / (DEFAULTASPECT * Width);
  174.       *Rotation = 0.0;
  175.       *Skew = 0.0;
  176.       if (*Magnification < 0)
  177.       {
  178.          *Magnification = -*Magnification;
  179.          *Rotation += 180;
  180.       }
  181.       return;
  182.    }
  183.  
  184.    /* set up triangle ABC, having sides abc */
  185.    /* side a = bottom, b = left, c = diagonal not containing (x3rd,y3rd) */
  186.    tmpx = xxmax - xx3rd;
  187.    tmpy = yymin - yy3rd;
  188.    a2 = tmpx*tmpx + tmpy*tmpy;
  189.    a = sqrt(a2);
  190.    *Rotation = -rad_to_deg(atan2( tmpy, tmpx )); /* negative for image rotation */
  191.  
  192.    tmpx = xxmin - xx3rd;
  193.    tmpy = yymax - yy3rd;
  194.    b2 = tmpx*tmpx + tmpy*tmpy;
  195.    b = sqrt(b2);
  196.  
  197.    tmpx = xxmax - xxmin;
  198.    tmpy = yymax - yymin;
  199.    c2 = tmpx*tmpx + tmpy*tmpy;
  200.  
  201.    tmpa = acos((a2+b2-c2)/(2*a*b)); /* save tmpa for later use */
  202.    *Skew = 90 - rad_to_deg(tmpa);
  203.  
  204.    *Xctr = (xxmin + xxmax)/2;
  205.    *Yctr = (yymin + yymax)/2;
  206.  
  207.    Height = b * sin(tmpa);
  208.    *Magnification  = 2/Height; /* 1/(h/2) */
  209.    *Xmagfactor = Height / (DEFAULTASPECT * a);
  210.    if (*Magnification < 0)
  211.       {
  212.       *Magnification = -*Magnification;
  213.       *Rotation += 180;
  214.       }
  215.    return;
  216. }
  217.  
  218. /* convert center/mag to corners */
  219. void cvtcorners(double Xctr, double Yctr, LDBL Magnification, double Xmagfactor, double Rotation, double Skew)
  220. {
  221.    double x, y;
  222.    double h, w; /* half height, width */
  223.    double tanskew, sinrot, cosrot;
  224.  
  225.    if (Xmagfactor == 0.0)
  226.       Xmagfactor = 1.0;
  227.  
  228.    h = (double)(1/Magnification);
  229.    w = h / (DEFAULTASPECT * Xmagfactor);
  230.  
  231.    if (Rotation == 0.0 && Skew == 0.0)
  232.       { /* simple, faster case */
  233.       xx3rd = xxmin = Xctr - w;
  234.       xxmax = Xctr + w;
  235.       yy3rd = yymin = Yctr - h;
  236.       yymax = Yctr + h;
  237.       return;
  238.       }
  239.  
  240.    /* in unrotated, untranslated coordinate system */
  241.    tanskew = tan(deg_to_rad(Skew));
  242.    xxmin = -w + h*tanskew;
  243.    xxmax =  w - h*tanskew;
  244.    xx3rd = -w - h*tanskew;
  245.    yymax = h;
  246.    yy3rd = yymin = -h;
  247.  
  248.    /* rotate coord system and then translate it */
  249.    Rotation = deg_to_rad(Rotation);
  250.    sinrot = sin(Rotation);
  251.    cosrot = cos(Rotation);
  252.  
  253.    /* top left */
  254.    x = xxmin * cosrot + yymax *  sinrot;
  255.    y = -xxmin * sinrot + yymax *  cosrot;
  256.    xxmin = x + Xctr;
  257.    yymax = y + Yctr;
  258.  
  259.    /* bottom right */
  260.    x = xxmax * cosrot + yymin *  sinrot;
  261.    y = -xxmax * sinrot + yymin *  cosrot;
  262.    xxmax = x + Xctr;
  263.    yymin = y + Yctr;
  264.  
  265.    /* bottom left */
  266.    x = xx3rd * cosrot + yy3rd *  sinrot;
  267.    y = -xx3rd * sinrot + yy3rd *  cosrot;
  268.    xx3rd = x + Xctr;
  269.    yy3rd = y + Yctr;
  270.  
  271.    return;
  272. }
  273.  
  274. /* convert corners to center/mag using bf */
  275. void cvtcentermagbf(bf_t Xctr, bf_t Yctr, LDBL *Magnification, double *Xmagfactor, double *Rotation, double *Skew)
  276. {
  277.    /* needs to be LDBL or won't work past 307 (-DBL_MIN_10_EXP) or so digits */
  278.    LDBL Width, Height;
  279.    LDBL a, b; /* bottom, left, diagonal */
  280.    LDBL a2, b2, c2; /* squares of above */
  281.    LDBL tmpx, tmpy;
  282.    double tmpa; /* temporary x, y, angle */
  283.    bf_t bfWidth, bfHeight;
  284.    bf_t bftmpx, bftmpy;
  285.    int saved;
  286.    int signx;
  287.  
  288.    saved = save_stack();
  289.  
  290.    /* simple normal case first */
  291.    /* if (xx3rd == xxmin && yy3rd == yymin) */
  292.    if(!cmp_bf(bfx3rd, bfxmin) && !cmp_bf(bfy3rd, bfymin))
  293.       { /* no rotation or skewing, but stretching is allowed */
  294.       bfWidth  = alloc_stack(bflength+2);
  295.       bfHeight = alloc_stack(bflength+2);
  296.       /* Width  = xxmax - xxmin; */
  297.       sub_bf(bfWidth, bfxmax, bfxmin);
  298.       Width  = bftofloat(bfWidth);
  299.       /* Height = yymax - yymin; */
  300.       sub_bf(bfHeight, bfymax, bfymin);
  301.       Height = bftofloat(bfHeight);
  302.       /* *Xctr = (xxmin + xxmax)/2; */
  303.       add_bf(Xctr, bfxmin, bfxmax);
  304.       half_a_bf(Xctr);
  305.       /* *Yctr = (yymin + yymax)/2; */
  306.       add_bf(Yctr, bfymin, bfymax);
  307.       half_a_bf(Yctr);
  308.       *Magnification  = 2/Height;
  309.       *Xmagfactor =  (double)(Height / (DEFAULTASPECT * Width));
  310.       *Rotation = 0.0;
  311.       *Skew = 0.0;
  312.       if (*Magnification < 0)
  313.          {
  314.          *Magnification = -*Magnification;
  315.          *Rotation += 180;
  316.          }
  317.       restore_stack(saved);
  318.       return;
  319.       }
  320.  
  321.    bftmpx = alloc_stack(bflength+2);
  322.    bftmpy = alloc_stack(bflength+2);
  323.  
  324.    /* set up triangle ABC, having sides abc */
  325.    /* side a = bottom, b = left, c = diagonal not containing (x3rd,y3rd) */
  326.    /* IMPORTANT: convert from bf AFTER subtracting */
  327.    /* tmpx = xxmax - xx3rd; */
  328.    sub_bf(bftmpx, bfxmax, bfx3rd);
  329.    tmpx = bftofloat(bftmpx);
  330.    /* tmpy = yymin - yy3rd; */
  331.    sub_bf(bftmpy, bfymin, bfy3rd);
  332.    tmpy = bftofloat(bftmpy);
  333.    a2 = tmpx*tmpx + tmpy*tmpy;
  334.    a = sqrtl(a2);
  335.  
  336.    /* divide tmpx and tmpy by |tmpx| so that double version of atan2() can be used */
  337.    /* atan2() only depends on the ratio, this puts it in double's range */
  338.    signx = sign(tmpx);
  339.    if(signx)
  340.       tmpy /= tmpx * signx;       /* tmpy = tmpy / |tmpx| */
  341.    *Rotation = (double)(-rad_to_deg(atan2( (double)tmpy, signx ))); /* negative for image rotation */
  342.  
  343.    /* tmpx = xxmin - xx3rd; */
  344.    sub_bf(bftmpx, bfxmin, bfx3rd);
  345.    tmpx = bftofloat(bftmpx);
  346.    /* tmpy = yymax - yy3rd; */
  347.    sub_bf(bftmpy, bfymax, bfy3rd);
  348.    tmpy = bftofloat(bftmpy);
  349.    b2 = tmpx*tmpx + tmpy*tmpy;
  350.    b = sqrtl(b2);
  351.  
  352.    /* tmpx = xxmax - xxmin; */
  353.    sub_bf(bftmpx, bfxmax, bfxmin);
  354.    tmpx = bftofloat(bftmpx);
  355.    /* tmpy = yymax - yymin; */
  356.    sub_bf(bftmpy, bfymax, bfymin);
  357.    tmpy = bftofloat(bftmpy);
  358.    c2 = tmpx*tmpx + tmpy*tmpy;
  359.  
  360.    tmpa = acos((double)((a2+b2-c2)/(2*a*b))); /* save tmpa for later use */
  361.    *Skew = 90 - rad_to_deg(tmpa);
  362.  
  363.    /* these are the only two variables that must be to big precision */
  364.    /* *Xctr = (xxmin + xxmax)/2; */
  365.    add_bf(Xctr, bfxmin, bfxmax);
  366.    half_a_bf(Xctr);
  367.    /* *Yctr = (yymin + yymax)/2; */
  368.    add_bf(Yctr, bfymin, bfymax);
  369.    half_a_bf(Yctr);
  370.  
  371.    Height = b * sin(tmpa);
  372.    *Magnification  = 2/Height; /* 1/(h/2) */
  373.    *Xmagfactor = (double)(Height / (DEFAULTASPECT * a));
  374.    if (*Magnification < 0)
  375.       {
  376.       *Magnification = -*Magnification;
  377.       *Rotation += 180;
  378.       }
  379.    restore_stack(saved);
  380.    return;
  381. }
  382.  
  383.  
  384. /* convert center/mag to corners using bf */
  385. void cvtcornersbf(bf_t Xctr, bf_t Yctr, LDBL Magnification, double Xmagfactor, double Rotation, double Skew)
  386. {
  387.    LDBL x, y;
  388.    LDBL h, w; /* half height, width */
  389.    LDBL xmin, ymin, xmax, ymax, x3rd, y3rd;
  390.    double tanskew, sinrot, cosrot;
  391.    bf_t bfh, bfw;
  392.    bf_t bftmp;
  393.    int saved;
  394.  
  395.    saved = save_stack();
  396.    bfh = alloc_stack(bflength+2);
  397.    bfw = alloc_stack(bflength+2);
  398.  
  399.    if (Xmagfactor == 0.0)
  400.       Xmagfactor = 1.0;
  401.  
  402.    h = 1/Magnification;
  403.    floattobf(bfh, h);
  404.    w = h / (DEFAULTASPECT * Xmagfactor);
  405.    floattobf(bfw, w);
  406.  
  407.    if (Rotation == 0.0 && Skew == 0.0)
  408.       { /* simple, faster case */
  409.       /* xx3rd = xxmin = Xctr - w; */
  410.       sub_bf(bfxmin, Xctr, bfw);
  411.       copy_bf(bfx3rd, bfxmin);
  412.       /* xxmax = Xctr + w; */
  413.       add_bf(bfxmax, Xctr, bfw);
  414.       /* yy3rd = yymin = Yctr - h; */
  415.       sub_bf(bfymin, Yctr, bfh);
  416.       copy_bf(bfy3rd, bfymin);
  417.       /* yymax = Yctr + h; */
  418.       add_bf(bfymax, Yctr, bfh);
  419.       restore_stack(saved);
  420.       return;
  421.       }
  422.  
  423.    bftmp = alloc_stack(bflength+2);
  424.    /* in unrotated, untranslated coordinate system */
  425.    tanskew = tan(deg_to_rad(Skew));
  426.    xmin = -w + h*tanskew;
  427.    xmax =  w - h*tanskew;
  428.    x3rd = -w - h*tanskew;
  429.    ymax = h;
  430.    y3rd = ymin = -h;
  431.  
  432.    /* rotate coord system and then translate it */
  433.    Rotation = deg_to_rad(Rotation);
  434.    sinrot = sin(Rotation);
  435.    cosrot = cos(Rotation);
  436.  
  437.    /* top left */
  438.    x =  xmin * cosrot + ymax *  sinrot;
  439.    y = -xmin * sinrot + ymax *  cosrot;
  440.    /* xxmin = x + Xctr; */
  441.    floattobf(bftmp, x);
  442.    add_bf(bfxmin, bftmp, Xctr);
  443.    /* yymax = y + Yctr; */
  444.    floattobf(bftmp, y);
  445.    add_bf(bfymax, bftmp, Yctr);
  446.  
  447.    /* bottom right */
  448.    x =  xmax * cosrot + ymin *  sinrot;
  449.    y = -xmax * sinrot + ymin *  cosrot;
  450.    /* xxmax = x + Xctr; */
  451.    floattobf(bftmp, x);
  452.    add_bf(bfxmax, bftmp, Xctr);
  453.    /* yymin = y + Yctr; */
  454.    floattobf(bftmp, y);
  455.    add_bf(bfymin, bftmp, Yctr);
  456.  
  457.    /* bottom left */
  458.    x =  x3rd * cosrot + y3rd *  sinrot;
  459.    y = -x3rd * sinrot + y3rd *  cosrot;
  460.    /* xx3rd = x + Xctr; */
  461.    floattobf(bftmp, x);
  462.    add_bf(bfx3rd, bftmp, Xctr);
  463.    /* yy3rd = y + Yctr; */
  464.    floattobf(bftmp, y);
  465.    add_bf(bfy3rd, bftmp, Yctr);
  466.  
  467.    restore_stack(saved);
  468.    return;
  469. }
  470.  
  471. #ifdef _MSC_VER
  472. #pragma optimize( "", on )
  473. #endif
  474.  
  475. void updatesavename(char *filename) /* go to the next file name */
  476. {
  477.    char *save, *hold;
  478.    char name[80],suffix[80];
  479.    char *dotptr;
  480.  
  481.    strcpy(name,filename);
  482.    suffix[0] = 0;
  483.    if ((dotptr = strrchr(name,'.')) != NULL
  484.      && dotptr > strrchr(name,SLASHC)) {
  485.       strcpy(suffix,dotptr);
  486.       *dotptr = 0;
  487.       }
  488.  
  489.    hold = name + strlen(name) - 1; /* start at the end */
  490.    while(hold >= name && (*hold == ' ' || isdigit(*hold))) /* skip backwards */
  491.       hold--;
  492.    hold++;            /* recover first digit */
  493.    while (*hold == '0')         /* skip leading zeros */
  494.       hold++;
  495.    save = hold;
  496.    while (*save) {        /* check for all nines */
  497.       if (*save != '9')
  498.      break;
  499.       save++;
  500.       }
  501.    if (!*save)            /* if the whole thing is nines then back */
  502.       save = hold - 1;        /* up one place. Note that this will eat */
  503.                 /* your last letter if you go to far.     */
  504.    else
  505.       save = hold;
  506.    sprintf(save,"%d",atoi(hold)+1); /* increment the number */
  507.    strcpy(filename,name);
  508.    strcat(filename,suffix);
  509. }
  510.  
  511. int check_writefile(char *name,char *ext)
  512. {
  513.  /* after v16 release, change encoder.c to also use this routine */
  514.    char openfile[80];
  515.    char opentype[20];
  516.    int i;
  517. nextname:
  518.    strcpy(openfile,name);
  519.    strcpy(opentype,ext);
  520.    for (i = 0; i < (int)strlen(openfile); i++)
  521.       if (openfile[i] == '.') {
  522.      strcpy(opentype,&openfile[i]);
  523.      openfile[i] = 0;
  524.      }
  525.    strcat(openfile,opentype);
  526.    if (access(openfile,0) != 0) /* file doesn't exist */
  527.    {
  528.       strcpy(name,openfile);
  529.       return 0;
  530.     }
  531.    /* file already exists */
  532.    if (overwrite == 0) {
  533.       updatesavename(name);
  534.       goto nextname;
  535.       }
  536.    return 1;
  537. }
  538.  
  539. /* ('check_key()' was moved to FRACTINT.C for MSC7-overlay speed purposes) */
  540. /* ('timer()'     was moved to FRACTINT.C for MSC7-overlay speed purposes) */
  541.  
  542. BYTE trigndx[] = {SIN,SQR,SINH,COSH};
  543. #ifndef XFRACT
  544. void (*ltrig0)(void) = lStkSin;
  545. void (*ltrig1)(void) = lStkSqr;
  546. void (*ltrig2)(void) = lStkSinh;
  547. void (*ltrig3)(void) = lStkCosh;
  548. void (*mtrig0)(void) = mStkSin;
  549. void (*mtrig1)(void) = mStkSqr;
  550. void (*mtrig2)(void) = mStkSinh;
  551. void (*mtrig3)(void) = mStkCosh;
  552. #endif
  553. void (*dtrig0)(void) = dStkSin;
  554. void (*dtrig1)(void) = dStkSqr;
  555. void (*dtrig2)(void) = dStkSinh;
  556. void (*dtrig3)(void) = dStkCosh;
  557.  
  558. struct trig_funct_lst trigfn[] =
  559. /* changing the order of these alters meaning of *.fra file */
  560. /* maximum 6 characters in function names or recheck all related code */
  561. {
  562. #ifndef XFRACT
  563.    {s_sin,   lStkSin,   dStkSin,   mStkSin   },
  564.    {s_cosxx, lStkCosXX, dStkCosXX, mStkCosXX },
  565.    {s_sinh,  lStkSinh,  dStkSinh,  mStkSinh  },
  566.    {s_cosh,  lStkCosh,  dStkCosh,  mStkCosh  },
  567.    {s_exp,   lStkExp,   dStkExp,   mStkExp   },
  568.    {s_log,   lStkLog,   dStkLog,   mStkLog   },
  569.    {s_sqr,   lStkSqr,   dStkSqr,   mStkSqr   },
  570.    {s_recip, lStkRecip, dStkRecip, mStkRecip }, /* from recip on new in v16 */
  571.    {s_ident, StkIdent,  StkIdent,  StkIdent  },
  572.    {s_cos,   lStkCos,   dStkCos,   mStkCos   },
  573.    {s_tan,   lStkTan,   dStkTan,   mStkTan   },
  574.    {s_tanh,  lStkTanh,  dStkTanh,  mStkTanh  },
  575.    {s_cotan, lStkCoTan, dStkCoTan, mStkCoTan },
  576.    {s_cotanh,lStkCoTanh,dStkCoTanh,mStkCoTanh},
  577.    {s_flip,  lStkFlip,  dStkFlip,  mStkFlip  },
  578.    {s_conj,  lStkConj,  dStkConj,  mStkConj  },
  579.    {s_zero,  lStkZero,  dStkZero,  mStkZero  },
  580.    {s_asin,  lStkASin,  dStkASin,  mStkASin  },
  581.    {s_asinh, lStkASinh, dStkASinh, mStkASinh },
  582.    {s_acos,  lStkACos,  dStkACos,  mStkACos  },
  583.    {s_acosh, lStkACosh, dStkACosh, mStkACosh },
  584.    {s_atan,  lStkATan,  dStkATan,  mStkATan  },
  585.    {s_atanh, lStkATanh, dStkATanh, mStkATanh },
  586.    {s_cabs,  lStkCAbs,  dStkCAbs,  mStkCAbs  },
  587.    {s_abs,   lStkAbs,   dStkAbs,   mStkAbs   },
  588.    {s_sqrt,  lStkSqrt,  dStkSqrt,  mStkSqrt  },
  589. #else
  590.    {s_sin,   dStkSin,   dStkSin,   dStkSin   },
  591.    {s_cosxx, dStkCosXX, dStkCosXX, dStkCosXX },
  592.    {s_sinh,  dStkSinh,  dStkSinh,  dStkSinh  },
  593.    {s_cosh,  dStkCosh,  dStkCosh,  dStkCosh  },
  594.    {s_exp,   dStkExp,   dStkExp,   dStkExp   },
  595.    {s_log,   dStkLog,   dStkLog,   dStkLog   },
  596.    {s_sqr,   dStkSqr,   dStkSqr,   dStkSqr   },
  597.    {s_recip, dStkRecip, dStkRecip, dStkRecip }, /* from recip on new in v16 */
  598.    {s_ident, StkIdent,  StkIdent,  StkIdent  },
  599.    {s_cos,   dStkCos,   dStkCos,   dStkCos   },
  600.    {s_tan,   dStkTan,   dStkTan,   dStkTan   },
  601.    {s_tanh,  dStkTanh,  dStkTanh,  dStkTanh  },
  602.    {s_cotan, dStkCoTan, dStkCoTan, dStkCoTan },
  603.    {s_cotanh,dStkCoTanh,dStkCoTanh,dStkCoTanh},
  604.    {s_flip,  dStkFlip,  dStkFlip,  dStkFlip  },
  605.    {s_conj,  dStkConj,  dStkConj,  dStkConj  },
  606.    {s_zero,  dStkZero,  dStkZero,  dStkZero  },
  607.    {s_asin,  dStkASin,  dStkASin,  dStkASin  },
  608.    {s_asinh, dStkASinh, dStkASinh, dStkASinh },
  609.    {s_acos,  dStkACos,  dStkACos,  dStkACos  },
  610.    {s_acosh, dStkACosh, dStkACosh, dStkACosh },
  611.    {s_atan,  dStkATan,  dStkATan,  dStkATan  },
  612.    {s_atanh, dStkATanh, dStkATanh, dStkATanh },
  613.    {s_cabs,  dStkCAbs,  dStkCAbs,  dStkCAbs  },
  614.    {s_abs,   dStkAbs,   dStkAbs,   dStkAbs   },
  615.    {s_sqrt,  dStkSqrt,  dStkSqrt,  dStkSqrt  },
  616. #endif
  617. };
  618. int numtrigfn = sizeof(trigfn)/sizeof(struct trig_funct_lst);
  619.  
  620. void showtrig(char *buf) /* return display form of active trig functions */
  621. {
  622.    char tmpbuf[30];
  623.    *buf = 0; /* null string if none */
  624.    trigdetails(tmpbuf);
  625.    if (tmpbuf[0])
  626.       sprintf(buf," function=%s",tmpbuf);
  627. }
  628.  
  629. static void trigdetails(char *buf)
  630. {
  631.    int i, numfn;
  632.    char tmpbuf[20];
  633.    if(fractype==JULIBROT || fractype==JULIBROTFP)
  634.       numfn = (fractalspecific[neworbittype].flags >> 6) & 7;
  635.    else
  636.       numfn = (curfractalspecific->flags >> 6) & 7;
  637.    if(curfractalspecific == &fractalspecific[FORMULA] ||
  638.       curfractalspecific == &fractalspecific[FFORMULA]    )
  639.       numfn = maxfn;
  640.    *buf = 0; /* null string if none */
  641.    if (numfn>0) {
  642.       strcpy(buf,trigfn[trigndx[0]].name);
  643.       i = 0;
  644.       while(++i < numfn) {
  645.      sprintf(tmpbuf,"/%s",trigfn[trigndx[i]].name);
  646.      strcat(buf,tmpbuf);
  647.      }
  648.       }
  649. }
  650.  
  651. /* set array of trig function indices according to "function=" command */
  652. int set_trig_array(int k, char *name)
  653. {
  654.    char trigname[10];
  655.    int i;
  656.    char *slash;
  657.    strncpy(trigname,name,6);
  658.    trigname[6] = 0; /* safety first */
  659.  
  660.    if ((slash = strchr(trigname,'/')) != NULL)
  661.       *slash = 0;
  662.  
  663.    strlwr(trigname);
  664.  
  665.    for(i=0;i<numtrigfn;i++)
  666.    {
  667.       if(strcmp(trigname,trigfn[i].name)==0)
  668.       {
  669.      trigndx[k] = (BYTE)i;
  670.      set_trig_pointers(k);
  671.      break;
  672.       }
  673.    }
  674.    return(0);
  675. }
  676. void set_trig_pointers(int which)
  677. {
  678.   /* set trig variable functions to avoid array lookup time */
  679.    int i;
  680.    switch(which)
  681.    {
  682.    case 0:
  683. #ifndef XFRACT
  684.       ltrig0 = trigfn[trigndx[0]].lfunct;
  685.       mtrig0 = trigfn[trigndx[0]].mfunct;
  686. #endif
  687.       dtrig0 = trigfn[trigndx[0]].dfunct;
  688.       break;
  689.    case 1:
  690. #ifndef XFRACT
  691.       ltrig1 = trigfn[trigndx[1]].lfunct;
  692.       mtrig1 = trigfn[trigndx[1]].mfunct;
  693. #endif
  694.       dtrig1 = trigfn[trigndx[1]].dfunct;
  695.       break;
  696.    case 2:
  697. #ifndef XFRACT
  698.       ltrig2 = trigfn[trigndx[2]].lfunct;
  699.       mtrig2 = trigfn[trigndx[2]].mfunct;
  700. #endif
  701.       dtrig2 = trigfn[trigndx[2]].dfunct;
  702.       break;
  703.    case 3:
  704. #ifndef XFRACT
  705.       ltrig3 = trigfn[trigndx[3]].lfunct;
  706.       mtrig3 = trigfn[trigndx[3]].mfunct;
  707. #endif
  708.       dtrig3 = trigfn[trigndx[3]].dfunct;
  709.       break;
  710.    default: /* do 'em all */
  711.       for(i=0;i<4;i++)
  712.      set_trig_pointers(i);
  713.       break;
  714.    }
  715. }
  716.  
  717. static FCODE sfractal_type[] =     {"Fractal type:"};
  718. static FCODE sitem_name[] =        {"Item name:"};
  719. static FCODE sitem_file[] =        {"Item file:"};
  720. static FCODE s3D_transform[] =     {"3D Transform"};
  721. static FCODE syou_are_cycling[] =  {"You are in color-cycling mode"};
  722. static FCODE sfloating_point[] =   {"Floating-point"};
  723. static FCODE ssolid_guessing[] =   {"Solid Guessing"};
  724. static FCODE sboundary_tracing[] = {"Boundary Tracing"};
  725. static FCODE stesseral[] =         {"Tesseral"};
  726. static FCODE scalculation_time[] = {"Calculation time:"};
  727. static FCODE siterations[] =       {" 1000's of points:"};
  728. static FCODE scornersxy[] =        {"Corners:                X                     Y"};
  729. static FCODE stop_left[] =         {"Top-l"};
  730. static FCODE sbottom_right[] =     {"Bot-r"};
  731. static FCODE sbottom_left[] =      {"Bot-l"};
  732. static FCODE scenter[] =           {"Ctr"};
  733. static FCODE struncate[] =         {"(Center values shown truncated to 320 decimals)"};
  734. static FCODE smag[] =              {"Mag"};
  735. static FCODE sxmag[] =             {"X-Mag-Factor"};
  736. static FCODE srot[] =              {"Rotation"};
  737. static FCODE sskew[] =             {"Skew"};
  738. static FCODE sparams[] =           {"Params "};
  739. static FCODE siteration_maximum[] ={"Iteration maximum: "};
  740. static FCODE seffective_bailout[] ={"     Effective bailout: "};
  741. static FCODE scurrent_rseed[] =    {"Current 'rseed': "};
  742. static FCODE sinversion_radius[] = {"Inversion radius: "};
  743. static FCODE sxcenter[] =          {"  xcenter: "};
  744. static FCODE sycenter[] =          {"  ycenter: "};
  745. static FCODE sparms_chgd[] = {"Parms chgd since generated"};
  746. static FCODE sstill_being[] = {"Still being generated"};
  747. static FCODE sinterrupted_resumable[] = {"Interrupted, resumable"};
  748. static FCODE sinterrupted_non_resumable[] = {"Interrupted, non-resumable"};
  749. static FCODE simage_completed[] = {"Image completed"};
  750. static FCODE sflag_is_activated[] = {" flag is activated"};
  751. static FCODE sinteger_math[]      = {"Integer math is in use"};
  752. static FCODE sin_use_required[] = {" in use (required)"};
  753. static FCODE sarbitrary_precision[] = {"Arbitrary precision "};
  754. static FCODE spressanykey[] = {"Press any key to continue, F6 for area, CTRL-TAB for next page"};
  755. static FCODE spressanykey1[] = {"Press any key to continue, Backspace for first screen"};
  756. static FCODE sbatch[] = {" (Batch mode)"};
  757. static FCODE ssavename[] = {"Savename: "};
  758. static FCODE sstopsecret[] = {"Top Secret Developer's Screen"};
  759. static FCODE sthreepass[] = {" (threepass)"};   
  760.  
  761. static void show_str_var(char *name, char *var, int *row, char *msg)
  762. {
  763.    if(var == NULL)
  764.       return;
  765.    if(*var != 0)
  766.    {
  767.       sprintf(msg,"%s=%s",name,var);
  768.       putstring((*row)++,2,C_GENERAL_HI,msg);
  769.    }
  770. }
  771.  
  772. int tab_display_2(char *msg)
  773. {
  774.    extern long maxptr, maxstack, startstack;
  775.    int row,key,ret=0;
  776.    helptitle();
  777.    setattr(1,0,C_GENERAL_MED,24*80); /* init rest to background */
  778.  
  779.    row = 1;
  780.    putstringcenter(row++,0,80,C_PROMPT_HI, sstopsecret);
  781.    sprintf(msg,"%u bytes conventional stack free",stackavail());
  782.    putstring(++row,2,C_GENERAL_HI,msg);
  783.    sprintf(msg,"%ld of %ld bignum memory used",maxptr,maxstack);
  784.    putstring(++row,2,C_GENERAL_HI,msg);
  785.    sprintf(msg,"   %ld used for bignum globals", startstack);
  786.    putstring(++row,2,C_GENERAL_HI,msg);
  787.    sprintf(msg,"   %ld stack used == %ld variables of length %d",
  788.          maxptr-startstack,(long)((maxptr-startstack)/(rbflength+2)),rbflength+2);
  789.    putstring(++row,2,C_GENERAL_HI,msg);
  790.    if(bf_math)
  791.    {
  792.       sprintf(msg,"intlength %-d bflength %-d ",intlength, bflength);
  793.       putstring(++row,2,C_GENERAL_HI,msg);
  794.    }
  795.    row++;   
  796.    show_str_var(s_tempdir,    tempdir,      &row, msg);
  797.    show_str_var(s_workdir,    workdir,      &row, msg);
  798.    show_str_var(s_printfile,  PrintName,    &row, msg);
  799.    show_str_var(s_filename,   readname,     &row, msg);
  800.    show_str_var(s_formulafile,FormFileName, &row, msg);
  801.    show_str_var(s_savename,   savename,     &row, msg);
  802.    show_str_var(s_parmfile,   CommandFile,  &row, msg);
  803.    show_str_var(s_ifsfile,    IFSFileName,  &row, msg);
  804.    show_str_var(s_autokeyname,autoname,     &row, msg);
  805.    show_str_var(s_lightname,  light_name,   &row, msg);
  806.    show_str_var(s_map,        MAP_name,     &row, msg);
  807.    sprintf(msg,"Sizeof fractalspecific array %d",
  808.       num_fractal_types*(int)sizeof(struct fractalspecificstuff));
  809.    putstring(row++,2,C_GENERAL_HI,msg);
  810.  
  811.    putstringcenter(24,0,80,C_GENERAL_LO,spressanykey1);
  812.    key=getakeynohelp();
  813.    if(key == BACKSPACE)
  814.       ret = 1;
  815.    return(ret);      
  816. }
  817.  
  818. int tab_display()    /* display the status of the current image */
  819. {
  820.    int row, i, j, addrow=0;
  821.    double Xctr, Yctr;
  822.    LDBL Magnification;
  823.    double Xmagfactor, Rotation, Skew;
  824.    bf_t bfXctr=NULL, bfYctr=NULL;
  825.    char msg[350];
  826.    char far *msgptr;
  827.    int key;
  828.    int saved=0;
  829.    int dec;
  830.  
  831.    if (calc_status < 0) {     /* no active fractal image */
  832.       return(0);        /* (no TAB on the credits screen) */
  833.    }
  834.    if (calc_status == 1)    /* next assumes CLK_TCK is 10^n, n>=2 */
  835.       calctime += (clock_ticks() - timer_start) / (CLK_TCK/100);
  836.    stackscreen();
  837.    if(bf_math)
  838.    {
  839.       saved = save_stack();
  840.       bfXctr = alloc_stack(bflength+2);
  841.       bfYctr = alloc_stack(bflength+2);
  842.    }
  843. top:
  844.    helptitle();
  845.    setattr(1,0,C_GENERAL_MED,24*80); /* init rest to background */
  846.    row = 2;
  847.    putstring(row,2,C_GENERAL_MED,sfractal_type);
  848.    if (display3d > 0)
  849.       putstring(row,16,C_GENERAL_HI,s3D_transform);
  850.    else {
  851.       putstring(row,16,C_GENERAL_HI,
  852.        curfractalspecific->name[0] == '*' ?
  853.          &curfractalspecific->name[1] :
  854.          curfractalspecific->name);
  855.       i = 0;
  856.       if (fractype == FORMULA || fractype == FFORMULA)
  857.       {
  858.          putstring(row+1,3,C_GENERAL_MED,sitem_name);
  859.      putstring(row+1,16,C_GENERAL_HI,FormName);
  860.          i = strlen(FormName)+1;
  861.          putstring(row+2,3,C_GENERAL_MED,sitem_file);
  862.          if(strlen(FormFileName) >= 29)
  863.             addrow = 1;
  864.          putstring(row+2+addrow,16,C_GENERAL_HI,FormFileName);
  865.       }
  866.       trigdetails(msg);
  867.       putstring(row+1,16+i,C_GENERAL_HI,msg);
  868.       if (fractype == LSYSTEM) 
  869.       {
  870.          putstring(row+1,3,C_GENERAL_MED,sitem_name);
  871.      putstring(row+1,16,C_GENERAL_HI,LName);
  872.          putstring(row+2,3,C_GENERAL_MED,sitem_file);
  873.          if(strlen(LFileName) >= 28)
  874.             addrow = 1;
  875.          putstring(row+2+addrow,16,C_GENERAL_HI,LFileName);
  876.       }
  877.       if (fractype == IFS || fractype == IFS3D) 
  878.       {
  879.          putstring(row+1,3,C_GENERAL_MED,sitem_name);
  880.      putstring(row+1,16,C_GENERAL_HI,IFSName);
  881.          putstring(row+2,3,C_GENERAL_MED,sitem_file);
  882.          if(strlen(IFSFileName) >= 28)
  883.             addrow = 1;
  884.          putstring(row+2+addrow,16,C_GENERAL_HI,IFSFileName);
  885.       }
  886.    }
  887.  
  888.    switch (calc_status) {
  889.       case 0:  msgptr = sparms_chgd;
  890.            break;
  891.       case 1:  msgptr = sstill_being;
  892.            break;
  893.       case 2:  msgptr = sinterrupted_resumable;
  894.            break;
  895.       case 3:  msgptr = sinterrupted_non_resumable;
  896.            break;
  897.       case 4:  msgptr = simage_completed;
  898.            break;
  899.       default: msgptr = "";
  900.       }
  901.    putstring(row,45,C_GENERAL_HI,msgptr);
  902.    if(initbatch && calc_status != 0)
  903.       putstring(-1,-1,C_GENERAL_HI,sbatch);
  904.    
  905.    if (helpmode == HELPCYCLING)
  906.       putstring(row+1,45,C_GENERAL_HI,syou_are_cycling);
  907.    ++row;
  908.    /* if(bf_math == 0) */ 
  909.      ++row;
  910.  
  911.     i = j = 0;
  912.     if (display3d > 0) {
  913.        if (usr_floatflag)
  914.       j = 1;
  915.        }
  916.     else
  917.        if (floatflag)
  918.       j = (usr_floatflag) ? 1 : 2;
  919.     if(bf_math==0)
  920.     {
  921.     if (j) {
  922.        putstring(row,45,C_GENERAL_HI,sfloating_point);
  923.  
  924.        putstring(-1,-1,C_GENERAL_HI,(j == 1) ? sflag_is_activated
  925.                          : sin_use_required );
  926.       i = 1;
  927.       }
  928.       else
  929.       {
  930.        putstring(row,45,C_GENERAL_HI,sinteger_math);
  931.       i = 1;
  932.       }
  933.    } else
  934.    {
  935.        sprintf(msg,"(%-d decimals)",decimals /*getprecbf(CURRENTREZ)*/);
  936.        putstring(row,45,C_GENERAL_HI,sarbitrary_precision);
  937.        putstring(-1,-1,C_GENERAL_HI,msg);
  938.  
  939.       i = 1;
  940.    }   
  941.  
  942.    row += i;
  943.  
  944.    if (calc_status == 1 || calc_status == 2)
  945.       if (curfractalspecific->flags&NORESUME)
  946.       {
  947.      static FCODE msg[] = {"Note: can't resume this type after interrupts other than <tab> and <F1>"};
  948.      putstring(row++,2,C_GENERAL_HI,msg);
  949.       }
  950.    row += addrow;
  951.    putstring(row,2,C_GENERAL_MED,ssavename);
  952.    putstring(row,-1,C_GENERAL_HI,savename);
  953.    
  954.    /* if(bf_math == 0) */
  955.      ++row;
  956.  
  957.    if (got_status >= 0 && (calc_status == 1 || calc_status == 2)) {
  958.       switch (got_status) {
  959.      case 0:
  960.         sprintf(msg,"%d Pass Mode",totpasses);
  961.         putstring(row,2,C_GENERAL_HI,msg);
  962.             if(usr_stdcalcmode=='3')
  963.                 putstring(row,-1,C_GENERAL_HI,sthreepass);
  964.         break;
  965.      case 1:
  966.         putstring(row,2,C_GENERAL_HI,ssolid_guessing);
  967.             if(usr_stdcalcmode=='3')
  968.                 putstring(row,-1,C_GENERAL_HI,sthreepass);
  969.         break;
  970.      case 2:
  971.         putstring(row,2,C_GENERAL_HI,sboundary_tracing);
  972.         break;
  973.      case 3:
  974.         sprintf(msg,"Processing row %d (of %d) of input image",currow,fileydots);
  975.         putstring(row,2,C_GENERAL_HI,msg);
  976.         break;
  977.      case 4:
  978.         putstring(row,2,C_GENERAL_HI,stesseral);
  979.         break;
  980.      }
  981.       ++row;
  982.       if (got_status != 3) {
  983.      sprintf(msg,"Working on block (y,x) [%d,%d]...[%d,%d], ",
  984.         yystart,xxstart,yystop,xxstop);
  985.      putstring(row,2,C_GENERAL_MED,msg);
  986.      if (got_status == 2 || got_status == 4) { /* btm or tesseral */
  987.         putstring(-1,-1,C_GENERAL_MED,"at ");
  988.         sprintf(msg,"[%d,%d]",currow,curcol);
  989.         putstring(-1,-1,C_GENERAL_HI,msg);
  990.         }
  991.      else {
  992.         if (totpasses > 1) {
  993.            putstring(-1,-1,C_GENERAL_MED,"pass ");
  994.            sprintf(msg,"%d",curpass);
  995.            putstring(-1,-1,C_GENERAL_HI,msg);
  996.            putstring(-1,-1,C_GENERAL_MED," of ");
  997.            sprintf(msg,"%d",totpasses);
  998.            putstring(-1,-1,C_GENERAL_HI,msg);
  999.            putstring(-1,-1,C_GENERAL_MED,", ");
  1000.            }
  1001.         putstring(-1,-1,C_GENERAL_MED,"at row ");
  1002.         sprintf(msg,"%d",currow);
  1003.         putstring(-1,-1,C_GENERAL_HI,msg);
  1004.         }
  1005.      ++row;
  1006.      }
  1007.       }
  1008.    putstring(row,2,C_GENERAL_MED,scalculation_time);
  1009.    sprintf(msg,"%3ld:%02ld:%02ld.%02ld", calctime/360000L,
  1010.       (calctime%360000L)/6000, (calctime%6000)/100, calctime%100);
  1011.    putstring(-1,-1,C_GENERAL_HI,msg);
  1012.    /* XXX */
  1013.  
  1014.    if ((curfractalspecific->flags&INFCALC) && (coloriter != 0)) {
  1015.       putstring(row,-1,C_GENERAL_MED,siterations);
  1016.       sprintf(msg," %ld of %ld",coloriter-2,maxct);
  1017.       putstring(row,-1,C_GENERAL_HI,msg);
  1018.    }
  1019.    
  1020.    ++row;
  1021.    if(bf_math == 0)
  1022.      ++row;
  1023.    if (videoentry.xdots && bf_math==0) {
  1024.       sprintf(msg,"Video: %dx%dx%d %s %s",
  1025.           videoentry.xdots, videoentry.ydots, videoentry.colors,
  1026.           videoentry.name, videoentry.comment);
  1027.       putstring(row++,2,C_GENERAL_MED,msg);
  1028.       }
  1029.    if(!(curfractalspecific->flags&NOZOOM))
  1030.    {
  1031.    adjust_corner(); /* make bottom left exact if very near exact */
  1032.    if(bf_math)
  1033.    {
  1034.       int truncate, truncaterow;
  1035.       dec = min(320,decimals);
  1036.       adjust_cornerbf(); /* make bottom left exact if very near exact */
  1037.       cvtcentermagbf(bfXctr, bfYctr, &Magnification, &Xmagfactor, &Rotation, &Skew);
  1038.       /* find alignment information */
  1039.       msg[0] = 0;
  1040.       truncate = 0;
  1041.       if(dec < decimals)
  1042.          truncate = 1;
  1043.       truncaterow = row;
  1044.       putstring(++row,2,C_GENERAL_MED,scenter);
  1045.       putstring(row,8,C_GENERAL_MED,s_x);
  1046.       bftostr(msg,dec,bfXctr);
  1047.       if(putstringwrap(&row,10,78,C_GENERAL_HI,msg,5)==1)
  1048.          truncate = 1;
  1049.       putstring(++row,8,C_GENERAL_MED,s_y);
  1050.       bftostr(msg,dec,bfYctr);
  1051.       if(putstringwrap(&row,10,78,C_GENERAL_HI,msg,5)==1 || truncate)
  1052.          putstring(truncaterow,2,C_GENERAL_MED,struncate);
  1053.       putstring(++row,2,C_GENERAL_MED,smag);
  1054. #ifdef USE_LONG_DOUBLE
  1055.       sprintf(msg,"%10.8Le",Magnification);
  1056. #else
  1057.       sprintf(msg,"%10.8le",Magnification);
  1058. #endif
  1059.       putstring(-1,11,C_GENERAL_HI,msg);
  1060.       putstring(++row,2,C_GENERAL_MED,sxmag);
  1061.       sprintf(msg,"%11.5f   ",Xmagfactor);
  1062.       putstring(-1,-1,C_GENERAL_HI,msg);
  1063.       putstring(-1,-1,C_GENERAL_MED,srot);
  1064.       sprintf(msg,"%9.3f   ",Rotation);
  1065.       putstring(-1,-1,C_GENERAL_HI,msg);
  1066.       putstring(-1,-1,C_GENERAL_MED,sskew);
  1067.       sprintf(msg,"%9.3f",Skew);
  1068.       putstring(-1,-1,C_GENERAL_HI,msg);
  1069.    }
  1070.    else /* bf != 1 */
  1071.    {
  1072.       putstring(row,2,C_GENERAL_MED,scornersxy);
  1073.       putstring(++row,3,C_GENERAL_MED,stop_left);
  1074.       sprintf(msg,"%20.16f  %20.16f",xxmin,yymax);
  1075.       putstring(-1,17,C_GENERAL_HI,msg);
  1076.       putstring(++row,3,C_GENERAL_MED,sbottom_right);
  1077.       sprintf(msg,"%20.16f  %20.16f",xxmax,yymin);
  1078.       putstring(-1,17,C_GENERAL_HI,msg);
  1079.  
  1080.       if (xxmin != xx3rd || yymin != yy3rd)
  1081.       {
  1082.          putstring(++row,3,C_GENERAL_MED,sbottom_left);
  1083.          sprintf(msg,"%20.16f  %20.16f",xx3rd,yy3rd);
  1084.          putstring(-1,17,C_GENERAL_HI,msg);
  1085.       }
  1086.       cvtcentermag(&Xctr, &Yctr, &Magnification, &Xmagfactor, &Rotation, &Skew);
  1087.       putstring(row+=2,2,C_GENERAL_MED,scenter);
  1088.       sprintf(msg,"%20.16f %20.16f  ",Xctr,Yctr);
  1089.       putstring(-1,-1,C_GENERAL_HI,msg);
  1090.       putstring(-1,-1,C_GENERAL_MED,smag);
  1091. #ifdef USE_LONG_DOUBLE
  1092.       sprintf(msg," %10.8Le",Magnification);
  1093. #else
  1094.       sprintf(msg," %10.8le",Magnification);
  1095. #endif
  1096.       putstring(-1,-1,C_GENERAL_HI,msg);
  1097.       putstring(++row,2,C_GENERAL_MED,sxmag);
  1098.       sprintf(msg,"%11.5f   ",Xmagfactor);
  1099.       putstring(-1,-1,C_GENERAL_HI,msg);
  1100.       putstring(-1,-1,C_GENERAL_MED,srot);
  1101.       sprintf(msg,"%9.3f   ",Rotation);
  1102.       putstring(-1,-1,C_GENERAL_HI,msg);
  1103.       putstring(-1,-1,C_GENERAL_MED,sskew);
  1104.       sprintf(msg,"%9.3f",Skew);
  1105.       putstring(-1,-1,C_GENERAL_HI,msg);
  1106.  
  1107.    }
  1108.    }      
  1109.    for (i = 0; i < MAXPARAMS; i++)
  1110.    {
  1111.       char *p;
  1112.       int col;
  1113.       p = typehasparm(fractype,i);
  1114.       if(i%4 == 0)
  1115.       {
  1116.          row++;
  1117.          col = 9;
  1118.       }
  1119.       else
  1120.          col = -1;
  1121.       if(p)
  1122.       {
  1123.          if(i==0)
  1124.             putstring(++row,2,C_GENERAL_MED,sparams);
  1125.          sprintf(msg,"%3d: ",i+1);
  1126.          putstring(row,col,C_GENERAL_MED,msg);
  1127.          if(*p == '+')
  1128.             sprintf(msg,"%-12d",(int)param[i]);
  1129.          else if(*p == '#')
  1130.             sprintf(msg,"%-12lu",(U32)param[i]);
  1131.          else   
  1132.             sprintf(msg,"%-12.9f",param[i]);
  1133.          putstring(-1,-1,C_GENERAL_HI,msg);
  1134.       }
  1135.    }
  1136.    putstring(row+=2,2,C_GENERAL_MED,siteration_maximum);
  1137.    sprintf(msg,"%ld",maxit);
  1138.    putstring(-1,-1,C_GENERAL_HI,msg);
  1139.    putstring(-1,-1,C_GENERAL_MED,seffective_bailout);
  1140.    sprintf(msg,"%f",rqlim);
  1141.    putstring(-1,-1,C_GENERAL_HI,msg);
  1142.  
  1143.    if (fractype == PLASMA) {
  1144.       putstring(++row,2,C_GENERAL_MED,scurrent_rseed);
  1145.       sprintf(msg,"%d",rseed);
  1146.       putstring(-1,-1,C_GENERAL_HI,msg);
  1147.       }
  1148.  
  1149.    if(invert) {
  1150.       putstring(++row,2,C_GENERAL_MED,sinversion_radius);
  1151.       sprintf(msg,"%12.9f",f_radius);
  1152.       putstring(-1,-1,C_GENERAL_HI,msg);
  1153.       putstring(-1,-1,C_GENERAL_MED,sxcenter);
  1154.       sprintf(msg,"%12.9f",f_xcenter);
  1155.       putstring(-1,-1,C_GENERAL_HI,msg);
  1156.       putstring(-1,-1,C_GENERAL_MED,sycenter);
  1157.       sprintf(msg,"%12.9f",f_ycenter);
  1158.       putstring(-1,-1,C_GENERAL_HI,msg);
  1159.       }
  1160.  
  1161.    if ((row += 2) < 23) ++row;
  1162. /*waitforkey:*/
  1163.    putstringcenter(/*row*/24,0,80,C_GENERAL_LO,spressanykey);
  1164.    movecursor(25,80);
  1165. #ifdef XFRACT
  1166.    while (keypressed()) {
  1167.        getakey();
  1168.    }
  1169. #endif
  1170.    key = getakeynohelp();
  1171.    if (key==F6) {
  1172.        unstackscreen();
  1173.        area();
  1174.        stackscreen();
  1175. /*       goto waitforkey;*/
  1176.         goto top;
  1177.    }
  1178.    else if(key==CTL_TAB) {    
  1179.       if(tab_display_2(msg))
  1180.          goto top;
  1181.    }
  1182.    unstackscreen();
  1183.    timer_start = clock_ticks(); /* tab display was "time out" */
  1184.    if(bf_math)
  1185.       restore_stack(saved);
  1186.    return(0);
  1187. }
  1188.  
  1189. static void area(void)
  1190. {
  1191.     /* apologies to UNIX folks, we PC guys have to save near space */
  1192.     static FCODE warning[] = {"Warning: inside may not be unique\n"};
  1193.     static FCODE total_area[] = {".  Total area "}; 
  1194.     char far *msg;
  1195.     int x,y;
  1196.     char buf[160];
  1197.     long cnt=0;
  1198.     if (inside<0) {
  1199.       static FCODE msg[] = {"Need solid inside to compute area"};
  1200.       stopmsg(0,msg);
  1201.       return;
  1202.     }
  1203.     for (y=0;y<ydots;y++) {
  1204.       for (x=0;x<xdots;x++) {
  1205.           if (getcolor(x,y)==inside) {
  1206.               cnt++;
  1207.           }
  1208.       }
  1209.     }
  1210.     if (inside>0 && outside<0 && maxit>inside) {
  1211.       msg = warning;
  1212.     } else {
  1213.       msg = (char far *)"";
  1214.     }
  1215. #ifndef XFRACT
  1216.       sprintf(buf,"%Fs%ld inside pixels of %ld%Fs%f",
  1217.               msg,cnt,(long)xdots*(long)ydots,(char far *)total_area,
  1218.               cnt/((float)xdots*(float)ydots)*(xxmax-xxmin)*(yymax-yymin));
  1219. #else
  1220.       sprintf(buf,"%s%ld inside pixels of %ld%s%f",
  1221.               msg,cnt,(long)xdots*(long)ydots,total_area,
  1222.               cnt/((float)xdots*(float)ydots)*(xxmax-xxmin)*(yymax-yymin));
  1223. #endif
  1224.     stopmsg(4,buf);
  1225. }
  1226.  
  1227. int endswithslash(char *fl)
  1228. {
  1229.    int len;
  1230.    len = strlen(fl);
  1231.    if(len)
  1232.       if(fl[--len] == SLASHC)
  1233.      return(1);
  1234.    return(0);
  1235. }
  1236.  
  1237. /* --------------------------------------------------------------------- */
  1238. static char seps[] = {"' ','\t',\n',\r'"};
  1239. char *get_ifs_token(char *buf,FILE *ifsfile)
  1240. {
  1241.    char *bufptr;
  1242.    for(;;)
  1243.    {
  1244.       if(file_gets(buf,200,ifsfile) < 0)
  1245.          return(NULL);
  1246.       else
  1247.       {
  1248.          if((bufptr = strchr(buf,';')) != NULL) /* use ';' as comment to eol */
  1249.             *bufptr = 0;
  1250.          if((bufptr = strtok(buf, seps)) != NULL)
  1251.             return(bufptr);
  1252.       }
  1253.    }
  1254. }
  1255.  
  1256. FCODE insufficient_ifs_mem[]={"Insufficient memory for IFS"};
  1257. int numaffine;
  1258. int ifsload()            /* read in IFS parameters */
  1259. {
  1260.    int i;
  1261.    FILE *ifsfile;
  1262.    char buf[201];
  1263.    char *bufptr;
  1264.    int ret,rowsize;
  1265.  
  1266.    if (ifs_defn) { /* release prior parms */
  1267.       farmemfree((char far *)ifs_defn);
  1268.       ifs_defn = NULL;
  1269.       }
  1270.  
  1271.    ifs_type = 0;
  1272.    rowsize = IFSPARM;
  1273.    if (find_file_item(IFSFileName,IFSName,&ifsfile) < 0)
  1274.       return(-1);
  1275.  
  1276.    file_gets(buf,200,ifsfile);
  1277.    if((bufptr = strchr(buf,';')) != NULL) /* use ';' as comment to eol */
  1278.       *bufptr = 0;
  1279.    
  1280.    strlwr(buf);
  1281.    bufptr = &buf[0];
  1282.    while (*bufptr) {
  1283.       if (strncmp(bufptr,"(3d)",4) == 0) {
  1284.      ifs_type = 1;
  1285.      rowsize = IFS3DPARM;
  1286.      }
  1287.       ++bufptr;
  1288.       }
  1289.  
  1290.    for (i = 0; i < (NUMIFS+1)*IFS3DPARM; ++i)
  1291.       ((float *)tstack)[i] = 0;
  1292.    i = ret = 0;
  1293.    bufptr = get_ifs_token(buf,ifsfile);
  1294.    while(bufptr != NULL)
  1295.    {
  1296.       if(sscanf(bufptr," %f ",&((float *)tstack)[i]) != 1)
  1297.          break ;
  1298.       if (++i >= NUMIFS*rowsize) 
  1299.       {
  1300.          static FCODE msg[]={"IFS definition has too many lines"};
  1301.         stopmsg(0,msg);
  1302.         ret = -1;
  1303.         break;
  1304.       }
  1305.       if((bufptr = strtok( NULL, seps ))==NULL)
  1306.       {
  1307.          if((bufptr = get_ifs_token(buf,ifsfile)) == NULL)
  1308.          {
  1309.             ret = -1;
  1310.             break;
  1311.          }   
  1312.       }
  1313.       if(ret == -1)
  1314.          break;
  1315.       if(*bufptr == '}')
  1316.          break;
  1317.    }
  1318.    
  1319.    if ((i % rowsize) != 0 || *bufptr != '}') {
  1320.       static FCODE msg[]={"invalid IFS definition"};
  1321.       stopmsg(0,msg);
  1322.       ret = -1;
  1323.       }
  1324.    if (i == 0 && ret == 0) {
  1325.       static FCODE msg[]={"Empty IFS definition"};
  1326.       stopmsg(0,msg);
  1327.       ret = -1;
  1328.       }
  1329.    fclose(ifsfile);
  1330.  
  1331.    if (ret == 0) {
  1332.       numaffine = i/rowsize;
  1333.       if ((ifs_defn = (float far *)farmemalloc(
  1334.             (long)((NUMIFS+1)*IFS3DPARM*sizeof(float)))) == NULL) {
  1335.      stopmsg(0,insufficient_ifs_mem);
  1336.      ret = -1;
  1337.      }
  1338.       else
  1339.      for (i = 0; i < (NUMIFS+1)*IFS3DPARM; ++i)
  1340.         ifs_defn[i] = ((float *)tstack)[i];
  1341.    }
  1342.    return(ret);
  1343. }
  1344. /* TW 5-31-94 - added search of current directory for entry files if
  1345.    entry item not found */
  1346.  
  1347. int find_file_item(char *filename,char *itemname,FILE **fileptr)
  1348. {
  1349.    FILE *infile=NULL;
  1350.    int found = 0;
  1351.    if((found=find_one_file_item(filename,itemname,&infile)) != 0) 
  1352.    {  /* search for file */
  1353.       int out;
  1354.       char drive[FILE_MAX_DRIVE];
  1355.       char dir[FILE_MAX_DIR];
  1356.       char fname[FILE_MAX_FNAME];
  1357.       char ext[FILE_MAX_EXT];
  1358.       char fullpath[FILE_MAX_PATH];
  1359.       splitpath(filename,drive,dir,fname,ext);
  1360.       makepath(fullpath,drive,dir,"*",ext);
  1361.       out = fr_findfirst(fullpath);
  1362.       found = 0;
  1363.       while(out == 0) 
  1364.       {
  1365.          char msg[200];
  1366.          DTA.filename[FILE_MAX_FNAME+FILE_MAX_EXT-2]=0;
  1367.          sprintf(msg,"Searching %13s for %s      ",DTA.filename,itemname);
  1368.          showtempmsg(msg);
  1369.          if(!(DTA.attribute & SUBDIR) && 
  1370.              strcmp(DTA.filename,".")&&
  1371.              strcmp(DTA.filename,"..")) {    
  1372. #ifndef XFRACT
  1373.             strlwr(DTA.filename);
  1374. #endif
  1375.             splitpath(DTA.filename,NULL,NULL,fname,ext);
  1376.             makepath(fullpath,drive,dir,fname,ext);
  1377.             if((found=find_one_file_item(fullpath,itemname,&infile)) == 0) 
  1378.             {
  1379.                strcpy(filename,fullpath);
  1380.                break;
  1381.             }   
  1382.          }   
  1383.          out = fr_findnext();
  1384.       }
  1385.       cleartempmsg();
  1386.       if(found != 0)
  1387.       {
  1388.          sprintf(fullpath,"'%s' file entry item not found",itemname);
  1389.          stopmsg(0,fullpath);
  1390.          return(-1);
  1391.       }
  1392.    }
  1393.    /* found file */   
  1394.    if(fileptr != NULL)
  1395.       *fileptr = infile;
  1396.    else if(infile != NULL)
  1397.       fclose(infile);   
  1398.    return(0);
  1399. }
  1400.  
  1401. static int find_one_file_item(char *filename,char *itemname,FILE **infile)
  1402. {
  1403.    char fullpathname[FILE_MAX_PATH];
  1404.    char fname[FILE_MAX_FNAME];
  1405.    char ext[FILE_MAX_EXT];
  1406.  
  1407.    /* first try current directory */
  1408.    splitpath(filename ,NULL,NULL,fname,ext);
  1409.    makepath(fullpathname,""   ,"" ,fname,ext);
  1410.    if(access(fullpathname,0)!=0)   /* not in current dir */
  1411.       strcpy(fullpathname,filename);   
  1412.  
  1413.    /* now binary node as of 2/95 TW */
  1414.    if ((*infile = fopen(fullpathname,"rb")) == NULL) {
  1415.        return(-1);
  1416.       }
  1417.    /* 
  1418.       Scan_entries() resuses code from gfe_choose_entry() in PROMPTS1.C. The
  1419.       original code used text mode, which made ftell() and fseek() unreliable
  1420.       in cases where files have garbage after the EOF.
  1421.     */
  1422.    if(scan_entries(*infile, NULL, itemname)<0)
  1423.       return(0);
  1424.    fclose(*infile);
  1425.    infile = NULL;
  1426.    return(-1);
  1427. }
  1428.  
  1429. int file_gets(char *buf,int maxlen,FILE *infile)
  1430. {
  1431.    int len,c;
  1432.    /* similar to 'fgets', but file may be in either text or binary mode */
  1433.    /* returns -1 at eof, length of string otherwise */
  1434.    if (feof(infile)) return -1;
  1435.    len = 0;
  1436.    while (len < maxlen) {
  1437.       if ((c = getc(infile)) == EOF || c == '\032') {
  1438.      if (len) break;
  1439.      return -1;
  1440.      }
  1441.       if (c == '\n') break;             /* linefeed is end of line */
  1442.       if (c != '\r') buf[len++] = (char)c;    /* ignore c/r */
  1443.       }
  1444.    buf[len] = 0;
  1445.    return len;
  1446. }
  1447.  
  1448. int first_err = 1;
  1449.  
  1450. #ifndef XFRACT
  1451. #ifdef WINFRACT
  1452. /* call this something else to dodge the QC4WIN bullet... */
  1453. int win_matherr( struct exception *except )
  1454. #else
  1455. int _cdecl matherr( struct exception *except )
  1456. #endif
  1457. {
  1458.     static FCODE msg[]={"Math error, but we'll try to keep going"};
  1459.     if(first_err)
  1460.     {
  1461.        if(debugflag == 4000 || debugflag == 3200)stopmsg(0,msg);
  1462.        first_err = 0;
  1463.     }
  1464.     if(debugflag)
  1465.     {
  1466.        static int ct = 0;
  1467.        static FILE *fp=NULL;
  1468.        if(fp==NULL)
  1469.       fp = fopen("matherr","w");
  1470.        if(ct++ < 100)
  1471.        {
  1472.       fprintf(fp,"err:  %d\nname: %s\narg:  %e\n",
  1473.           except->type, except->name, except->arg1);
  1474.       fflush(fp);
  1475.        }
  1476.     }
  1477.     if( except->type == DOMAIN )
  1478.     {
  1479.     char buf[40];
  1480.     sprintf(buf,"%e",except->arg1);
  1481.     /* This test may be unnecessary - from my experiments if the
  1482.        argument is too large or small the error is TLOSS not DOMAIN */
  1483.     if(strstr(buf,"IN")||strstr(buf,"NAN"))  /* trashed arg? */
  1484.                /* "IND" with MSC, "INF" with BC++ */
  1485.     {
  1486.        if( strcmp( except->name, s_sin ) == 0 )
  1487.        {
  1488.           except->retval = 0.0;
  1489.           return(1);
  1490.        }
  1491.        else if( strcmp( except->name, s_cos ) == 0 )
  1492.        {
  1493.           except->retval = 1.0;
  1494.           return(1);
  1495.        }
  1496.        else if( strcmp( except->name, s_log ) == 0 )
  1497.        {
  1498.           except->retval = 1.0;
  1499.           return(1);
  1500.        }
  1501.        }
  1502.     }
  1503.     if( except->type == TLOSS )
  1504.     {
  1505.        /* try valiantly to keep going */
  1506.        if( strcmp( except->name, s_sin ) == 0 )
  1507.        {
  1508.           except->retval = 0.5;
  1509.           return(1);
  1510.        }
  1511.        else if( strcmp( except->name, s_cos ) == 0 )
  1512.        {
  1513.           except->retval = 0.5;
  1514.           return(1);
  1515.        }
  1516.     }
  1517.     /* shucks, no idea what went wrong, but our motto is "keep going!" */
  1518.     except->retval = 1.0;
  1519.     return(1);
  1520. }
  1521. #endif
  1522.  
  1523. void roundfloatd(double *x) /* make double converted from float look ok */
  1524. {
  1525.    char buf[30];
  1526.    sprintf(buf,"%-10.7g",*x);
  1527.    *x = atof(buf);
  1528. }
  1529.  
  1530. /* fake a keystroke, returns old pending key */
  1531. int ungetakey(int key)
  1532. {
  1533.    int old;
  1534.    old = keybuffer;
  1535.    keybuffer = key;
  1536.    return(old);
  1537. }
  1538.  
  1539. #if _MSC_VER == 800
  1540. #ifdef FIXTAN_DEFINED
  1541. #undef tan
  1542. /* !!!!! stupid MSVC tan(x) bug fix !!!!!!!!            */
  1543. /* tan(x) can return -tan(x) if -pi/2 < x < pi/2       */
  1544. /* if tan(x) has been called before outside this range. */
  1545. double fixtan( double x )
  1546.    {
  1547.    double y;
  1548.  
  1549.    y = tan(x);
  1550.    if ((x > -PI/2 && x < 0 && y > 0) || (x > 0 && x < PI/2 && y < 0))
  1551.       y = -y;
  1552.    return y;
  1553.    }
  1554. #define tan fixtan
  1555. #endif
  1556. #endif
  1557.  
  1558.